﻿
// opencv_demo1.cpp: 定义应用程序的类行为。
//

#include "pch.h"
#include "watermask_cv_dct.h"


/**
     * <pre>
     *     添加图片文字水印
     * <pre>
     * @author Yangxiaohui
     * @date 2018-10-25 19:16
     * @param image             图片对象
     * @param watermarkText     水印文字
     */

 Mat watermask_cv_dct::addImageWatermarkWithText(Mat image, std::string watermarkText) 
 {
     Mat complexImage;
    //优化图像的尺寸
    //Mat padded = optimizeImageDim(image);
    Mat padded = splitSrc(image);
    padded.convertTo(padded, CV_32F);
    std::vector<Mat> planes;
    planes.push_back(padded);
    planes.push_back(Mat::zeros(padded.size(), CV_32F));
    merge(planes, complexImage);

    // dft
    dft(complexImage, complexImage);

    // 添加文本水印
    Scalar scalar(0);
    Point point(40, 40);
   // putText(complexImage, watermarkText, point, FONT_HERSHEY_DUPLEX, 1, scalar);
   // flip(complexImage, complexImage, -1);
    putText(complexImage, watermarkText, point, FONT_HERSHEY_DUPLEX, 1, scalar);
   // flip(complexImage, complexImage, -1);
    return antitransformImage(complexImage, m_allPlanes);
}


/**
 * <pre>
 *     获取图片水印
 * <pre>
 * @author Yangxiaohui
 * @date 2018-10-25 19:58
 * @param image
 */
Mat watermask_cv_dct::getImageWatermarkWithText(Mat image) {
    
    Mat complexImage;
    Mat padded = splitSrc(image);
    padded.convertTo(padded, CV_32F);

    std::vector<Mat> planes;
    planes.push_back(padded);
    planes.push_back(Mat::zeros(padded.size(), CV_32F));
    merge(planes, complexImage);
    // dft
    dft(complexImage, complexImage);
    Mat magnitude = createOptimizedMagnitude(complexImage);
    planes.clear();
    return magnitude;
}

Mat watermask_cv_dct::splitSrc(Mat mat) {
    //原则上在第一个通道叠加
   // mat = optimizeImageDim(mat);   //原代码有这个步骤
    //split(mat, m_allPlanes);

    Mat yuvImage(mat.size(), CV_8UC3);
    cvtColor(mat, yuvImage, CV_BGR2YUV);
    split(yuvImage, m_allPlanes);
        
        Mat padded;
        if (m_allPlanes.size() > 1) {
        for (int i = 0; i < m_allPlanes.size(); i++) {
            if (i == 0) {
                //padded = allPlanes.get(i);
                padded = m_allPlanes.at(i);
                break;
            }
        }
    }
    else {
        padded = mat;
    }
    return padded;
}
 Mat watermask_cv_dct::antitransformImage(Mat complexImage, std::vector<Mat> allPlanes) {
    Mat invDFT;
    idft(complexImage, invDFT, DFT_SCALE | DFT_REAL_OUTPUT, 0);
   // idct(complexImage, invDFT, DFT_SCALE | DFT_REAL_OUTPUT);
    Mat restoredImage;
    invDFT.convertTo(restoredImage, CV_8U);
   
    if (allPlanes.size() == 0) {
        allPlanes.push_back(restoredImage);
    }
    else {
       // allPlanes.set(0, restoredImage);
        allPlanes[0] = restoredImage;
    }
    Mat lastImage;
    merge(allPlanes, lastImage);

    //返回rgb格式mat
    Mat bgrImage;
    cvtColor(lastImage, bgrImage, CV_YUV2BGR);

    return bgrImage;
}
/**
 * <pre>
 *     为加快傅里叶变换的速度，对要处理的图片尺寸进行优化
 * <pre>
 * @author Yangxiaohui
 * @date 2018-10-25 19:33
  * @param image
 * @return
 */
 Mat watermask_cv_dct::optimizeImageDim(Mat image) {
#if 0
    Mat padded;
    int addPixelRows = getOptimalDFTSize(image.rows());
    int addPixelCols = getOptimalDFTSize(image.cols());
    Imgproc.copyMakeBorder(image, padded, 0, addPixelRows - image.rows(), 0, addPixelCols - image.cols(),
        Imgproc.BORDER_CONSTANT, Scalar.all(0));

    return padded;
#else
     return image;
#endif
}
Mat watermask_cv_dct::createOptimizedMagnitude(Mat complexImage) {
    std::vector<Mat> newPlanes;
    Mat mag;
    split(complexImage, newPlanes);
    magnitude(newPlanes.at(0), newPlanes.at(1), mag);
    add(Mat::ones(mag.size(), CV_32F), mag, mag);
    log(mag, mag);
    shiftDFT(mag);
    mag.convertTo(mag, CV_8UC1);
    normalize(mag, mag, 0, 255, NORM_MINMAX, CV_8UC1);
    return mag;
}
void watermask_cv_dct::shiftDFT(Mat image) {
    //image = image.submat(new Rect(0, 0, image.cols() & -2, image.rows() & -2));
    //cvGetSubRect(image, image, Rect(0, 0, image.cols & -2, image.rows & -2));

    int cx = image.cols / 2;
    int cy = image.rows / 2;

    //Mat q0 = new Mat(image, new Rect(0, 0, cx, cy));
    Mat q0(image, Rect(0, 0, cx, cy));
    Mat q1(image, Rect(cx, 0, cx, cy));
    Mat q2(image, Rect(0, cy, cx, cy));
    Mat q3(image, Rect(cx, cy, cx, cy));
    Mat tmp;
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);
    q1.copyTo(tmp);
    q2.copyTo(q1);
    tmp.copyTo(q2);
}